/*********************************************************************
                         searchroutine.c
contains the search menu for all classes of keyset
cari 7/5/4 - change to allow parameters for last 3 marker searchers
*********************************************************************/
#include "fpp.h"
#include "clam.h"

extern int NewSearchClass;
extern int Clam_bandInt();
extern int list10clones();

void unattachedclones(void);
void searchclonetype(int type);
void multiplefpnum(void);
void clonesnofp(int);
void listdeleted(void);
void menu_main(void);
void subclonesearch(void);
void remsearch(void);
void notremsearch(void);
void gelsearch(void);
void creationdates_clone(int result,BOOL created);
void creationdates_marker(int result,BOOL created);
void ctgclonesearch(void);
void gtNbands(void);
void searchcommandmarker(void);
void listmultiplecontigs(void);
void listnocontigs(void);
void subcontigsearch(void);
void searchselected(void);
void searchpick(int box, float x, float y);
void find_contaminated();

extern void precompute_sulston();
extern int loadCz();
extern int ZscoreCpM();

static int lastsearchpick=0;
static void quit() {
   if(graphActivate(gsearch)) graphDestroy();
}

void searchcommandmarker()
{
static MENUOPT amenu[] = {
    { quit, "Close" },
    { 0, 0 } } ;

  int i, searchbox[lastSea+1];
  float line;
  
  if(graphActivate(gsearch)){
    graphClear();
  }
  else{
    gsearch = graphCreate (TEXT_FIT,"Marker Commands",.2,.2,.45,.28); 
    graphRegister(PICK,searchpick);
  }
  graphMenu(amenu);

  i = 1;
  line = 2.0;
  
  searchbox[i] = graphBoxStart();
  graphText("Marker Name                 Substring",2.0,line);
  graphBoxEnd();
  
  line +=2.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Before created date         dd/mm/yy hh:mm",2.0,line);
  graphBoxEnd();
  line +=1.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("After created date          dd/mm/yy hh:mm",2.0,line);
  graphBoxEnd();
  line +=1.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Before modified date        dd/mm/yy hh:mm",2.0,line);
  graphBoxEnd();
  line +=1.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("After modified date         dd/mm/yy hh:mm",2.0,line);
  graphBoxEnd();

  line +=2.0;      
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Remark                      Substring of remark",2.0,line);
  graphBoxEnd();

  line +=1.0;      
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Without Remark              Substring of remark",2.0,line);
  graphBoxEnd();
  
  line +=2.0;
  i=SeaMultCtg;
  searchbox[i] = graphBoxStart();
  graphText(">  N Contigs                Number",2.0,line);
  graphBoxEnd();
  
  line +=1.0;
  i=SeaNoCtg;
  searchbox[i] = graphBoxStart();
  graphText("<= N Contigs                Number",2.0,line);
  graphBoxEnd();
  
  line +=1.0;
  i=Sea10Clones;
  searchbox[i] = graphBoxStart();
  graphText(">  N Clones                 Number",2.0,line);
  graphBoxEnd();
  line +=1.0;

  i=SeaType;
  searchbox[i] = graphBoxStart();
  graphText("Marker Type                 String",2.0,line);
  graphBoxEnd();
  graphRedraw();
}

/*******************************************************
            DEF: searchpick
item picked from search command window
********************************************************/
void searchpick(int box, float x, float y)
{
int boxoffset;
    if(box <=0) return;

    if(classctg == CTGCLASS){
      printf("No contig search command window\n");
    }
    else if(classctg == CLONECLASS){
      if(lastsearchpick==box){       /* first click */
	if(box <= lastCloneInputSea) searchtype=box;
        else {      /* bypasses searchEngine, so check for new class */
            if (NewSearchClass) getlist();
	    if(box == SeaSingle)  unattachedclones();
	    else if(box == SeaMultFp) multiplefpnum();
	    else if(box == SeaNoFp) clonesnofp(0);
	    else if(box == SeaSelect) searchselected();
	    else if(box == SeaCancel) listdeleted(); 
	    else if(box == SeaContaminated) find_contaminated(); 
	    else if(box == SeaFull) searchclonetype(FULLX); 
	    else if(box == SeaHalf) searchclonetype(HALFX); 
	    else if(box == SeaGap) searchclonetype(GAPCLOSURE); 
        }
	menu_main();
      }
      else{                         /* second click */
	if(lastsearchpick != 0)
	  graphBoxDraw(lastsearchpick,BLACK,WHITE);
	lastsearchpick = box;
	graphBoxDraw(lastsearchpick,WHITE,BLACK);
	graphRedraw();
      }
    }
    else if(classctg == SEQCLASS){
    }
    else{   /* MARKERCLASS */
      boxoffset= box+lastCloneInputSea+1;
      if(lastsearchpick==box){     /* first click */
	if(box <= lastGeneralSea)
            searchtype =box;  
        else if (boxoffset>lastCloneSea && boxoffset <=lastSea)
            searchtype = boxoffset;
        else if (NewSearchClass) getlist();
	menu_main();
	graphPop();
      }
      else{                      /* second click */
	if(lastsearchpick != 0 && lastsearchpick<=lastSea)
	   graphBoxDraw(lastsearchpick,BLACK,WHITE);
	lastsearchpick = box;
	graphBoxDraw(lastsearchpick,WHITE,BLACK);
	graphRedraw();
      }
    }
}

void searchclone()
{
static MENUOPT amenu[] = {
    { quit, "Close" },
    { 0, 0 } } ;
  int searchbox[31];
  int i,seawidth,seaheight;
  float line;

  if(graphActivate(gsearch)){
    graphClear();
  }
  else{
    gsearch = graphCreate (TEXT_FIT,"Clone Commands",.2,.2,.5,.55) ; 
    graphRegister(PICK,searchpick);
  }
  graphMenu(amenu);
  
  i = 1;
  line = 2.0;
  
  searchbox[i] = graphBoxStart();
  graphText("Clone Name               Substring",2.0,line);
  graphBoxEnd();

  line +=2.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Before created date      dd/mm/yy hh:mm",2.0,line);
  graphBoxEnd();
  line +=1.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("After created date       dd/mm/yy hh:mm",2.0,line);
  graphBoxEnd();
  line +=1.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Before modified date     dd/mm/yy hh:mm",2.0,line);
  graphBoxEnd();
  line +=1.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("After modified date      dd/mm/yy hh:mm",2.0,line);
  graphBoxEnd();

  line +=2.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Remark                   Substring of remark",2.0,line);
  graphBoxEnd();
  line +=1.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Without Remark           Substring of remark",2.0,line);
  graphBoxEnd();

  line +=2.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Gel                      Identifier",2.0,line);
  graphBoxEnd();
 
  line +=2.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Match Clone              Clone name",2.0,line);
  graphBoxEnd();

  line +=2.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Contig                   Number",2.0,line);
  graphBoxEnd();
  
  line +=2.0; /* Cari 12/30/03 */
  i++;
  searchbox[i] = graphBoxStart();
  graphText("> N Bands                Number",2.0,line);
  graphBoxEnd();

  graphFitBounds(&seawidth,&seaheight);
  graphLine(0.0,line+2.0,seawidth,line+2.0);
  
  line +=4.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Singletons",2.0,line);
  graphBoxEnd();

  line +=2.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Multiple Fingerprints",2.0,line);
  graphBoxEnd();

  line +=1.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("No Fingerprints",2.0,line);
  graphBoxEnd();

  line +=2.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Selected (Ignore current keyset)",2.0,line);
  graphBoxEnd();
  
  line +=2.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Canceled (Ignore current keyset)",2.0,line);
  graphBoxEnd();
  
  line +=2.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Full-X",2.0,line);
  graphBoxEnd();

  line +=1.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Half-X",2.0,line);
  graphBoxEnd();

  line +=1.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Gap-closure",2.0,line);
  graphBoxEnd();

  line +=2.0;
  i++;
  searchbox[i] = graphBoxStart();
  graphText("Contaminated             ",2.0,line);
  graphBoxEnd();

  lastsearchpick = searchbox[searchtype];
  graphBoxDraw(lastsearchpick,WHITE,BLACK);
  graphRedraw();
}

void searchcommand()
{
  if(classctg == CTGCLASS){
      printf("For Contigs, the only search command is Name.\n");
      printf("See Project Window/Menu for searching on contig remarks.");
    }
    else if(classctg == CLONECLASS){
      searchclone();
      graphPop();
    }
    else if(classctg == SEQCLASS){

    }
    else{
      searchcommandmarker();
      graphPop();
    }
}

void unattachedclones()
{
  int count = 0;
  CLONE *clone;
  BOOL first = TRUE;
  struct list *p=NULL,*oldroot,*temp,*q;
  char str1[100];

  searchtype=SeaSingle; 
  if (NewSearchClass) {
      menu_main();
      getlist(); /* i have it on the pull-down, bypasses searchEngine
                                    and search command menu. */
  }
  oldroot = listroot;
  q = listroot;
  listroot = NULL;
  if(!dataloaded) return;

  while(q!=NULL){
      count++;
      clone =arrp(acedata, q->index, CLONE);
      if(clone->ctg == 0 && clone->clone[0] != '!'){
	if(first){
	  listroot  = (struct list *)messalloc((sizeof(struct list)));
	  listroot->next = NULL;
	  p = listroot;
	  p->index = q->index;
	  first = FALSE;

	  }
	else{
	  p->next = (struct list *)messalloc((sizeof(struct list)));
	  p=p->next;
	  p->index = q->index;
	}
      }
      q=q->next;
  }
  if(listroot==NULL){
      sprintf(str1,"Clone search (Singletons) failed for keyset of %d items.",count);
      displaymess(str1);
      listroot = oldroot;
      displaykeyset(0);
  }
  else{
      page = 0;
      if(p!=NULL){
	p->next = NULL;
	p= oldroot;
      }
      while(p!=NULL){
	temp=p;
	p=p->next;
	if(!messfree(temp))
	  printf("error freeing list memory\n");
      }
      displaykeyset(1);
   } 
   graphPop();
}

void multiplefpnum()
{
  int count = 0;
  CLONE *clone;
  BOOL first = TRUE;
  struct list *p=NULL,*oldroot,*temp,*q;
  char str1[100];

  oldroot = listroot;
  q = listroot;
  listroot = NULL;
  if(!dataloaded) return;

  while(q!=NULL){
      count++;
      clone =arrp(acedata, q->index, CLONE);
      if(clone->fp != NULL){
	if(clone->fp->next != NULL){
	  if(first){
	    listroot  = (struct list *)messalloc((sizeof(struct list)));
	    listroot->next = NULL;
	    p = listroot;
	    p->index = q->index;
	    first = FALSE;

	  }
	  else{
	    p->next = (struct list *)messalloc((sizeof(struct list)));
	    p=p->next;
	    p->index = q->index;
	  }
	}
      }
      q=q->next;
  }
  if(listroot==NULL){
      sprintf(str1,"Clone search (Multiple fingerprints) failed for keyset of %d items.",count);
      displaymess(str1);
      listroot = oldroot;
      displaykeyset(0);
  }
  else{
      page = 0;
      if(p!=NULL){
	p->next = NULL;
	p= oldroot;
      }
      while(p!=NULL){
	temp=p;
	p=p->next;
	if(!messfree(temp))
	  printf("error freeing list memory\n");
      }
      displaykeyset(1);
  }
  searchtype=SeaMultFp; 
  graphPop();
}

void clonesnofp(int min)
{
  int count = 0;
  CLONE *clone;
  BOOL first = TRUE;
  struct list *p=NULL,*oldroot,*temp,*q;
  char str1[100];

  q = listroot;
  oldroot = listroot;
  listroot = NULL;
  if(!dataloaded) return;

  while(q!=NULL){
      clone =arrp(acedata, q->index, CLONE);
      count++;
      if(clone->fp != NULL){
	if(clone->fp->b2 <=min){
	  if(first){
	    listroot  = (struct list *)messalloc((sizeof(struct list)));
	    listroot->next = NULL;
	    p = listroot;
	    p->index = q->index;
	    first = FALSE;
	  }
	  else{
	    p->next = (struct list *)messalloc((sizeof(struct list)));
	    p=p->next;
	    p->index = q->index;
	    count++;
	  }
	}
      }
      else{
        if(first){
          listroot  = (struct list *)messalloc((sizeof(struct list)));
          listroot->next = NULL;
          p = listroot;
          p->index = q->index;
          first = FALSE;
        }
        else{
          p->next = (struct list *)messalloc((sizeof(struct list)));
          p=p->next;
          p->index = q->index;
	}
      }
      q = q->next;
   }
   if(listroot==NULL){
      sprintf(str1,"Clone search (<= %d bands) failed for keyset of %d items.",min, count);
      displaymess(str1);
      listroot = oldroot;
      displaykeyset(0);
   }
   else{
      page = 0;
      if(p!=NULL){
	p->next = NULL;
	p= oldroot;
      }
      while(p!=NULL){
	temp=p;
	p=p->next;
	if(!messfree(temp))
	  printf("error freeing list memory\n");
      }
      displaykeyset(1);
    }
    if (min==0) searchtype=SeaNoFp; 
    graphPop();
}

void sortlist(int count)
{
  int i,j;
  struct list *p1,*p2;
  int temp;

  for(i=0;i<count-1;i++){    
    p1 = listroot;
    for(j=0;j<count-1;j++){
      p2= p1;
      p1 = p1->next;
      if(p1->index <  p2->index){
	temp = p2->index;
	p2->index = p1->index;
	p1->index = temp;
      }
    }
  }
}

void searchselected()
{
  struct contig *pctg;
  struct list *p=NULL,*oldroot,*temp;
  BOOL first = TRUE;
  CLONE *clone;
  int count = 0;
  char str1[100];

  if (currentctg<=0) {
      displaymess("Must have a contig with clone selected.");
      return;
  }
  oldroot = listroot;
  listroot = NULL;

  pctg = root; /* set pointer to start of clone data for this contig */
  while(pctg != NULL){
    clone = arrp(acedata,pctg->next, CLONE);  /* get clone data */
    if(clone->selected){
      count++;
      if(first){
	listroot  = (struct list *)messalloc((sizeof(struct list)));
	listroot->next = NULL;
	p = listroot;
	p->index = pctg->next;
	first = FALSE;
      }
      else{
	p->next = (struct list *)messalloc((sizeof(struct list)));
	p=p->next;
	p->index = pctg->next;
      }
    }
    pctg = pctg->new;
  }
  if(listroot==NULL){
    sprintf(str1,"Clone search (Selected) failed for Ctg%d.",currentctg);
    displaymess(str1);
    listroot = oldroot;
    displaykeyset(0);
  }
  else{
    page = 0;
    p= oldroot;
    while(p!=NULL){
      temp=p;
      p=p->next;
      if(!messfree(temp))
        printf("error freeing list memory\n");
    }
    sortlist(count);
    displaykeyset(1);
  }
  searchtype=SeaSelect; 
  graphPop();
}

int plate_neighbors_old(char* c1, char* c2)
{
    int ret = 0;
    int i1,i2;

    if (0 == strncmp(c1,c2,5) && abs(c1[5] - c2[5]) < 4 )
    {
        sscanf(&c1[6],"%d",&i1);
        sscanf(&c2[6],"%d",&i2);
        if (abs(i1 - i2) < 4)
        {
            ret = 1;
        }
    }
    return ret;
}

// We assume names like <lib name><plate num><well>
int plate_neighbors(char* c1, char* c2)
{
    int i1,i2;
    int len1,len2;
    int i;

    len1 = strlen(c1);
    len2 = strlen(c2);

    if (len1 != len2) return 0;
    if (len1 < 4) return 0; // we need at least a plate number followed by well
    
    // compare row letter 

    i = len1 - 3;
    if (abs(c1[i] - c2[i]) >= 4) return 0;

    // compare column number

    i = len1 - 2;
    sscanf(&c1[i],"%d",&i1);
    sscanf(&c2[i],"%d",&i2);
    if (abs(i1 - i2) >= 4) return 0;

    // now compare the plate numbers digit by digit

    if (!isdigit(c1[len1-4])) return 0;
    if (!isdigit(c2[len2-4])) return 0;

    for (i = len1 - 4; i >= 0; i--)
    {
        if (!isdigit(c1[i])) break;        
        if (!isdigit(c2[i])) break; 

        if (c1[i] != c2[i]) return 0;       
    }
     
    return 1;

}

void find_contaminated()
{
    int i, j;
    struct list* oldroot;
    struct list** ppnext;
    struct list* pnew;
    char* used_clones;
    int exponent;

    if (!arrayExists(bands))
    { 
        if (fpRead() == -1) 
        {
            fprintf(stderr,"ERROR: cannot read band file\n");
            return;
        }
    }
    precompute_sulston();

    oldroot = listroot;
    listroot = NULL; 
    ppnext = &listroot;

    used_clones = (char*)malloc(arrayMax(acedata)*sizeof(char));
    memset(used_clones,0,arrayMax(acedata)*sizeof(char));

    for (i = 0; i < arrayMax(acedata); i++)
    {
        printf("%d    \r",i);fflush(0);
        if (!loadCz(&C1z, i)) continue;
        if (C1z.clone[0] == '!') continue;
        for (j = i + 1; j < arrayMax(acedata); j++)
        {
            if (!loadCz(&C2z, j)) continue;
            if (C2z.clone[0] == '!') continue;
            if (!plate_neighbors(C1z.clone,C2z.clone)) continue;

            Zsulston(&C1z,&C2z,&Sz);
            exponent = ZscoreCpM(&C1z,&C2z,&Sz);

            if (exponent == 0) continue;

            printf("%s %s e-%d     \n",C1z.clone,C2z.clone,exponent);fflush(0);
            used_clones[i] = 1;
            used_clones[j] = 1;
        }
    }

    for (i = 0; i < arrayMax(acedata); i++)
    {
        if (used_clones[i] == 1)
        {
            pnew  = (struct list *)messalloc((sizeof(struct list)));
            pnew->index = i;
            pnew->next = 0;
            *ppnext = pnew; 
            ppnext = &pnew->next;
        }

    }
    free(used_clones);

    if(listroot == NULL)
    {
        displaymess("Clone search (Cancelled) failed for dataset.");
        listroot = oldroot;
        displaykeyset(0);
    }
    else
    {
        displaykeyset(1);
    }    
}


/*************************************************************
              DEF: listdeleted
Cancelled clones
***************************************************************/
void listdeleted()
{
  struct list *p=NULL,*temp,*oldroot;
  int j;
  BOOL found,first;

  oldroot = listroot;
  listroot = NULL; /* set to zero. Test at the end the value of listroot */

  j=0;
  found = FALSE;
  first= TRUE;
  while(!found){
    if(arrp(acedata,j,CLONE)->clone[0] == '!'){
      if(first){
        listroot  = (struct list *)messalloc((sizeof(struct list)));
        listroot->index = j;
        listroot->next = NULL;
        p = listroot;
        first = FALSE;
      }
      else{
        p->next = (struct list *)messalloc((sizeof(struct list)));
        p=p->next;
        p->index = j;
      }
     
    }
    else
      found = TRUE;
    j++;
  }
  if(listroot == NULL){
    displaymess("Clone search (Cancelled) failed for dataset.");
    listroot = oldroot;
    displaykeyset(0);
  }
  else{
    page = 0;
    p= oldroot;
    while(p!=NULL){
      temp=p;
      p=p->next;
      if(!messfree(temp))
        printf("error freeing list memory\n");
    }
    displaykeyset(1);
  }
  searchtype = SeaCancel;
  graphPop();
}
/***********************************************************
              DEF: searchclonetype
************************************************************/
void searchclonetype(int type)
{
  int count = 0;
  CLONE *clone;
  BOOL first = TRUE;
  struct list *p=NULL,*oldroot,*temp,*q;
  char str1[100];

  if (type==FULLX) searchtype=SeaFull;
  else if (type==HALFX) searchtype=SeaHalf;
  else if (type==GAPCLOSURE) searchtype=SeaGap;
  oldroot = listroot;
  q = listroot;
  listroot = NULL;
  if(!dataloaded) return;

  while(q!=NULL){
      count++;
      clone =arrp(acedata, q->index, CLONE);
      if(clone->seqtype == type){
	if(first){
	  listroot  = (struct list *)messalloc((sizeof(struct list)));
	  listroot->next = NULL;
	  p = listroot;
	  p->index = q->index;
	  first = FALSE;

	  }
	else{
	  p->next = (struct list *)messalloc((sizeof(struct list)));
	  p=p->next;
	  p->index = q->index;
	}
      }
      q=q->next;
  }
  if(listroot==NULL){
      sprintf(str1,"Clone search (%s) failed for keyset of %d items.",
                    seqtype[type], count);
      displaymess(str1);
      listroot = oldroot;
      displaykeyset(0);
  }
  else{
      page = 0;
      if(p!=NULL){
	p->next = NULL;
	p= oldroot;
      }
      while(p!=NULL){
	temp=p;
	p=p->next;
	if(!messfree(temp))
	  printf("error freeing list memory\n");
      }
      displaykeyset(1);
   } 
   graphPop();
}
